package com.hcss.common.util;

import org.springframework.cglib.beans.BeanCopier;
import org.springframework.cglib.core.Converter;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
 * @function : bean复制工具
 * 主要使用net.sf.cglib.beans.BeanCopier类，该类创建时消耗较大，建议静态化该类
 * Converter需要将需要的类型全部判断写入，BeanCopier只会只用参数converter
 */
public class BeanCopyUtil {
	/**
	 * 复制集合
	 * @param sources 源集合
	 * @param targetClz 目标集合
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	public static<T> List<T> copyList(List<?> sources, Class<T> targetClz) throws InstantiationException, IllegalAccessException{
		if(EmptyUtil.isEmpty(sources)){
			return null;
		}
		List<T> result = new ArrayList<T>();
		for(Object object : sources){
			T target = copy(object, targetClz);
			result.add(target);
		}
		
		return result;
	}
	
	/**
	 * 复制集合
	 * @param sources 源集合
	 * @param targetClz 目标集合
	 * @param beanCopier 静态BeanCopier对象，减少反复创建BeanCopier对象的消耗
	 * @param <T>
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	public static<T> List<T> copyList(List<?> sources, Class<T> targetClz, BeanCopier beanCopier) throws InstantiationException, IllegalAccessException{
		if(EmptyUtil.isEmpty(sources)){
			return null;
		}
		List<T> result = new ArrayList<T>();
		for(Object object : sources){
			T target = copy(object, targetClz, beanCopier);
			result.add(target);
		}
		
		return result;
	}
	
	/**
	 * 复制集合
	 * @param sources 源集合
	 * @param targetClz 目标集合
	 * @param beanCopier 静态BeanCopier对象，减少反复创建BeanCopier对象的消耗
	 * @param converter 自定义转换类，要求考虑全部转换类型否则会有null值错误
	 * @param <T>
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	public static<T> List<T> copyList(List<?> sources, Class<T> targetClz, BeanCopier beanCopier, Converter converter) throws InstantiationException, IllegalAccessException{
		if(EmptyUtil.isEmpty(sources)){
			return null;
		}
		List<T> result = new ArrayList<T>();
		for(Object object : sources){
			T target = copy(object, targetClz, beanCopier, converter);
			result.add(target);
		}
		
		return result;
	}
	
	/**
	 * 按照指定的对象类型进行复制
	 * @param source 源对象
	 * @param targetClz 目标类型
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	public static<T> T copy(Object source, Class<T> targetClz) throws InstantiationException, IllegalAccessException{
		T target = null;
		target = targetClz.newInstance();
		
		return copy(source, target);
	}
	
	/**
	 * 按照指定的对象类型进行复制
	 * @param source 源对象
	 * @param targetClz 目标类型
	 * @param beanCopier 静态BeanCopier对象，减少反复创建BeanCopier对象的消耗
	 * @param <T>
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	public static<T> T copy(Object source, Class<T> targetClz, BeanCopier beanCopier) throws InstantiationException, IllegalAccessException{
		T target = null;
		target = targetClz.newInstance();
		
		return copy(source, target, beanCopier);
	}
	
	/**
	 * 按照指定的对象类型进行复制
	 * @param source 源对象
	 * @param targetClz 目标类型
	 * @param beanCopier 静态BeanCopier对象，减少反复创建BeanCopier对象的消耗
	 * @param converter 自定义转换类，要求考虑全部转换类型否则会有null值错误
	 * @param <T>
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	public static<T> T copy(Object source, Class<T> targetClz, BeanCopier beanCopier, Converter converter) throws InstantiationException, IllegalAccessException{
		T target = null;
		target = targetClz.newInstance();
		
		return copy(source, target, beanCopier, converter);
	}
	
	/**
	 * 对象的属性值复制到另一个对象属性值
	 * @param source 源对象
	 * @param target 目标对象
	 * @return
	 */
	public static<T> T copy(Object source, T target){
		if(EmptyUtil.isHaveEmpty(source,target)){
			return target;
		}
		Object targetSource = null;
		try {
			targetSource = copyConvey(source,source.getClass());
		} catch (Exception e) {
			targetSource = source;
		}
		
		BeanCopier copier = BeanCopier.create(targetSource.getClass(), target.getClass(), false);
		copier.copy(targetSource, target, null);
		
		return target;
	}
	
	/**
	 * 对象的属性值复制到另一个对象属性值
	 * @param source 源对象
	 * @param target 目标对象
	 * @param beanCopier 静态BeanCopier对象，减少反复创建BeanCopier对象的消耗
	 * @param <T>
	 * @return
	 */
	public static<T> T copy(Object source, T target, BeanCopier beanCopier){
		beanCopier.copy(source, target, null);
		return target;
	}
	
	/**
	 * 对象的属性值复制到另一个对象属性值
	 * @param source 源对象
	 * @param target 目标对象
	 * @param beanCopier 静态BeanCopier对象，减少反复创建BeanCopier对象的消耗，要求useConvert=true
	 * @param converter 自定义转换类，要求考虑全部转换类型否则会有null值错误
	 * @param <T>
	 * @return
	 */
	public static<T> T copy(Object source, T target, BeanCopier beanCopier, Converter converter){
		beanCopier.copy(source, target, converter);
		return target;
	}
	
	/**
	 * 将目标的数据转换成指定的类型，主要考虑源对象的属性的类型都是字符串
	 * @param source
	 * @param targetClaz
	 * @return
	 * @throws Exception
	 */
	public static<T> T copyConvey(Object source, Class<T> targetClaz) throws Exception{
		if(EmptyUtil.isHaveEmpty(source, targetClaz)){
			return null;
		}
		List<Field> fields = ReflectUtil.getAllFields(source.getClass());
		if(EmptyUtil.isEmpty(fields)){
			return null;
		}
		T target = targetClaz.newInstance();
		
		Object sourceFieldValue = null;
		String sourceFieldName = null;
		Object targetFieldValue = null;
		for(Field field : fields){
			sourceFieldName = field.getName();
			sourceFieldValue = ReflectUtil.getValue(source, sourceFieldName);
			
			Field targetField = ReflectUtil.getField(targetClaz, sourceFieldName);
			if(EmptyUtil.isHaveEmpty(sourceFieldValue, targetField)){// 目标没有这个字段就跳过
				continue;
			}
			
			Class<?> sourceFieldClaz = field.getType();
			Class<?> targetFieldClaz = targetField.getType();
			
			if(sourceFieldClaz.equals(targetFieldClaz)){
				targetFieldValue = sourceFieldValue;
			}else if(sourceFieldClaz.equals(String.class) && ReflectUtil.isBasicClass(targetFieldClaz)){
				targetFieldValue = targetFieldClaz.getConstructor(String.class).newInstance(String.valueOf(sourceFieldValue));
			}else if(sourceFieldClaz.equals(String.class) && targetFieldClaz.equals(Date.class)){
				targetFieldValue = DateUtil.stringToDate(sourceFieldValue.toString(), DateUtil.getDateFormat(sourceFieldValue.toString()));
			}else if(sourceFieldClaz.equals(String.class) && targetFieldClaz.equals(BigDecimal.class)){
				targetFieldValue = new BigDecimal(sourceFieldValue.toString());
			}else{
				continue;
			}
			ReflectUtil.setValue(target, sourceFieldName, targetFieldValue);
		}
		return target;
	}
	
	/**
	 * 将源的非空属性值复制给目标对象
	 * @param source
	 * @param target
	 */
	public static<D> void copyNotNull(Object source, D target){
		if(EmptyUtil.isHaveEmpty(source, target)){
			return;
		}
		List<Field> fields = ReflectUtil.getAllFields(source.getClass());
		for(Field one : fields){
			try {
				String attrName = one.getName();
				Object value = ReflectUtil.getValue(source, attrName);
				if(EmptyUtil.isHaveEmpty(value)){
					continue;
				}
				ReflectUtil.setValue(target, attrName, value);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 按照指定的域集合进行复制
	 * @param source
	 * @param target
	 * @param fieldNames
	 * @throws Exception
	 */
	public static void copy(Object source, Object target, List<String> fieldNames) throws Exception{
		if(EmptyUtil.isHaveEmpty(source, target) || EmptyUtil.isEmpty(fieldNames)){
			return;
		}
		
		for(String fieldName : fieldNames){
			Object value = ReflectUtil.getValue(source, fieldName);
			ReflectUtil.setValue(target, fieldName, value);
		}
	}
}
